#include "trans_file_server.h"
#include "../timeoutManager/timeoutManager.h"

/* Usage:  */
int get_file_from_serv(tlv_msg_t cmd_msg, user_session_t *user_session)
{
    // 接收客户端文件名
    char filename[4096] = {0};
    memcpy(filename, cmd_msg.value, cmd_msg.hdr.length);
    // 检查当前文件夹是否有对应文件
    int netfd = user_session->netfd;
    tlv_msg_t send_pack;
    bzero(&send_pack, sizeof(send_pack));
    // 查询当前目录下是否有客户所要文件
    char md5_value_record[33] = {0};
    int if_file_exist = CheckFileExist(user_session, filename, md5_value_record);
    if (if_file_exist == -1)
    {
        printf("getsfile文件查询，数据库操作失败\n");
        return -1;
    }
    //------------------------------------------------------------
    if (if_file_exist == 1)
    {
        // 本地文件存在
        send_pack.hdr.type = GETS_FILE_EXIST;
        // 文件以哈希值命名，所以用哈希值去打开文件，开始下载
        int fd = open(md5_value_record, O_RDWR);
        printf("文件哈希值为：%s\n", md5_value_record);
        struct stat file_info;
        bzero(&file_info, sizeof(file_info));
        fstat(fd, &file_info);
        off_t file_length = file_info.st_size;
        send_pack.hdr.length = sizeof(file_length);
        printf("准备传文件，文件长度为%ld\n", file_length);
        memcpy(send_pack.value, &file_length, sizeof(file_length));
        // 将文件长度传给客户端
        ssize_t send_sret = tlv_send(netfd, &send_pack);
        if (send_sret == 1)
        {
            printf("客户端下线\n");
            return 1;
        }
        tlv_msg_t recv_pack;
        // 获取客户端现有的文件长度
        bzero(&recv_pack, sizeof(recv_pack));
        ssize_t recv_sret = tlv_recv(netfd, &recv_pack);
        if (recv_sret == 1)
        {
            printf("客户端下线\n");
            return 1;
        }
        // 获取客户端现有的文件长度
        off_t current_file_length;
        memcpy(&current_file_length, recv_pack.value, recv_pack.hdr.length);
        // 剩下的需要继续传输的文件长度
        off_t rest_file_length = file_length - current_file_length;
        off_t limit_file_length = 100000000;
        //------------------------------------------------------------
        // 文件大于100mb使用mmap传输
        if (rest_file_length > limit_file_length)
        {
            // 剩余文件大小大于100mb使用mmap进行文件传输
            int get_ret = getsfile_big(netfd, fd, file_length, current_file_length);
            if (get_ret == 1)
            {
                printf("客户端断连\n");
                close(fd);
                return 1;
            }
        }
        else
        {
            // 剩余文件大小小于100mb使用read函数进行进行文件传输
            int get_ret = getsfiel_small(netfd, fd, file_length, current_file_length);
            if (get_ret == 1)
            {
                printf("客户端断连\n");
                close(fd);
                return 1;
            }
        }
        close(fd);
        //------------------------------------------------------------
    }
    else if (if_file_exist == 0)
    {
        // 本地文件不存在
        send_pack.hdr.type = GETS_FILE_NOEXIST;
        char *response = "文件不存在，下载失败";
        send_pack.hdr.length = strlen(response);
        memcpy(send_pack.value, response, strlen(response));
        ssize_t send_sret = tlv_send(netfd, &send_pack);
        if (send_sret == 1)
        {
            printf("客户端下线\n");
            return 1;
        }
    }
    return 0;
}

int getsfile_big(int netfd, int fd, off_t file_length, off_t current_file_length)
{
    tlv_msg_t send_pack;
    bzero(&send_pack, sizeof(send_pack));
    // 占据磁盘空间
    if (ftruncate(fd, file_length) == -1)
    {
        perror("ftruncate failed");
    }
    off_t offset_length = (current_file_length / 4096) * 4096;
    off_t rest_mapping_length = file_length - offset_length;
    char *p = (char *)mmap(NULL, rest_mapping_length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset_length);
    // 本次累计发送的字节数量
    off_t send_length_thisturn = current_file_length - offset_length;
    // 每次发出的数据包长度
    int send_data_once;
    // 专门声明个用于数据发送的包
    tlv_msg_t send_data_pack;
    ssize_t send_sret;
    while (current_file_length < file_length)
    {
        bzero(&send_data_pack, sizeof(send_data_pack));
        send_data_once = ((file_length - current_file_length) < 4096) ? (file_length - current_file_length) : 4096;
        send_data_pack.hdr.type = DATA_CHUNK;
        send_data_pack.hdr.length = send_data_once;
        memcpy(send_data_pack.value, p + send_length_thisturn, send_data_once);
        // 错误检查
        if (send_data_once != 4096)
        {
            printf("%d\n", send_data_once);
        }
        send_sret = tlv_send(netfd, &send_data_pack);
        if (send_sret == 1)
        {
            munmap(p, rest_mapping_length);
            printf("大文件下载过程中，客户端下线\n");
            return 1;
        }

        timeout_manager_tick(&g_timeout_manager); // 刷新超时管理器，防止长时间传输过程中超时断开连接

        send_length_thisturn += send_data_once;
        current_file_length += send_data_once;
    }
    munmap(p, rest_mapping_length);

    bzero(&send_data_pack, sizeof(send_pack));
    send_data_pack.hdr.type = DATA_END;
    char *trans_finish = "大内容传输完成";
    printf("他要的东西我已经传完啦\n");
    send_data_pack.hdr.length = strlen(trans_finish);
    memcpy(send_data_pack.value, trans_finish, send_data_pack.hdr.length);
    send_sret = tlv_send(netfd, &send_data_pack);
    if (send_sret == 1)
    {
        printf("下载传输结束，客户端下线\n");
        return 1;
    }
    printf("%s\n", trans_finish);
    return 0;
}

int getsfiel_small(int netfd, int fd, off_t file_length, off_t current_file_length)
{
    char buf[4096];
    bzero(buf, sizeof(buf));
    tlv_msg_t send_data_pack;
    bzero(&send_data_pack, sizeof(send_data_pack));
    // 根据现有长度偏移
    lseek(fd, current_file_length, SEEK_SET);
    int send_data_once;
    // int i = 0;
    ssize_t send_sret;
    while (current_file_length < file_length)
    {
        // printf("i = %d\n",i++);
        bzero(&send_data_pack, sizeof(send_data_pack));
        send_data_pack.hdr.type = DATA_CHUNK;
        bzero(buf, sizeof(buf));
        send_data_once = read(fd, buf, sizeof(buf));

        // printf("%d\n",send_data_once);
        if (send_data_once == 0)
        {
            printf("通过read的文件传输结束\n");
            break;
        }
        // 错误打印
        if (send_data_once != 4096)
        {
            printf("%d\n", send_data_once);
        }
        send_data_pack.hdr.length = send_data_once;
        memcpy(send_data_pack.value, buf, send_data_once);
        send_sret = tlv_send(netfd, &send_data_pack);
        // 客户端断连接
        if (send_sret == 1)
        {
            printf("小文件下载过程中，客户端下线\n");
            return 1;
        }

        timeout_manager_tick(&g_timeout_manager); // 刷新超时管理器，防止长时间传输过程中超时断开连接

        current_file_length += send_data_once;
    }

    bzero(&send_data_pack, sizeof(send_data_pack));
    send_data_pack.hdr.type = DATA_END;
    char *trans_finish = "小内容传输完成";
    printf("他要的东西我已经传完啦\n");
    send_data_pack.hdr.length = strlen(trans_finish);
    memcpy(send_data_pack.value, trans_finish, send_data_pack.hdr.length);
    send_sret = tlv_send(netfd, &send_data_pack);
    if (send_sret == 1)
    {
        printf("下载传输结束，客户端下线\n");
        return 1;
    }
    printf("%s\n", trans_finish);

    return 0;
}
